package com.xjnt.base.support.admin.shiro.realm;

import java.util.List;
import java.util.Set;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.jfinal.aop.Duang;
import com.jfinal.plugin.activerecord.tx.Tx;
import com.xjnt.base.support.admin.entity.Account;
import com.xjnt.base.support.admin.entity.Group;
import com.xjnt.base.support.admin.entity.Permission;
import com.xjnt.base.support.admin.entity.Role;
import com.xjnt.base.support.admin.service.AccountService;
import com.xjnt.base.support.admin.service.GroupService;
import com.xjnt.base.support.admin.service.PermissionService;
import com.xjnt.base.support.admin.service.RoleService;

/**
 * @FileName : ShiroJdbcRealm.java
 * @Description :
 * @Copyright : Copyright (c) 2015
 * @author caoyong
 * @date Jul 31, 2015 12:20:18 PM
 */
public class ShiroJdbcRealm extends AuthorizingRealm {
	
	private static final AccountService accountService = Duang.duang(AccountService.class, Tx.class);
	private static final GroupService groupService = Duang.duang(GroupService.class, Tx.class);
	private static final RoleService roleService = Duang.duang(RoleService.class, Tx.class);
	private static final PermissionService permissionService = Duang.duang(PermissionService.class, Tx.class);
	
	/**
	 * 获取身份验证相关信息
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		// token 信息
		UsernamePasswordToken userToken = (UsernamePasswordToken) token;
		String username = userToken.getUsername();
		Account account = accountService.findByName(username);
		if (null != account) {
			if (account.getInt(Account.LOCKED) == 0) {
				SimpleAuthenticationInfo authInfo = new SimpleAuthenticationInfo(account, account.getStr(Account.PASSWORD), getName());
				clearCachedAuthorizationInfo(authInfo.getPrincipals());
				return authInfo;
			} else {
				throw new LockedAccountException();
			}
		} else {
			throw new UnknownAccountException();
		}
	}

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
		// TODO 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
		String loginName = ((Account) principal.fromRealm(getName()).iterator().next()).getStr(Account.USERNAME);
		SimpleAuthorizationInfo authInfo = new SimpleAuthorizationInfo();
		Set<String> setRoles = Sets.newHashSet(); // 角色集合
		Set<String> setPermissions = Sets.newHashSet(); // 权限集合
		List<Role> userRoles = Lists.newArrayList();
		Account account = accountService.findByName(loginName);
		if (account == null) {
			SecurityUtils.getSubject().logout();
		} else {
			if(account.getInt(Account.SUPER) == 1){
				userRoles = roleService.findAll();
			}else {
				userRoles = roleService.findByAccountId(account.getStr(Account.PK_ID));
				List<Group> groups = groupService.findByAccountId(account.getStr(Account.PK_ID));
				if (groups != null && !groups.isEmpty()) {
					String[] gIds = new String[groups.size()];
					int i = 0;
					for (Group group : groups) {
						gIds[i] = group.getStr(Group.PK_ID);
						i++;
					}
					List<Role> groupRoles = roleService.findByGroupIds(gIds);
					// 去除重复,并集
					groupRoles.removeAll(userRoles);
					userRoles.addAll(groupRoles);
				}
			}
		}
		loadRoles(setRoles, setPermissions, userRoles);
		authInfo.setRoles(setRoles);
		authInfo.setStringPermissions(setPermissions);
		return authInfo;
	}

	private void loadRoles(Set<String> setRoles, Set<String> setPermissions, List<Role> roles) {
		List<Permission> permissions = null;
		for (Role role : roles) {
			if (role.getInt(Role.AVAILABLE) == 1) {
				setRoles.add(role.getStr(Role.CODE));
				permissions = permissionService.findByRoleId(role.getStr(Role.PK_ID));
				loadPermissions(setPermissions, permissions);
			}
		}
	}

	private void loadPermissions(Set<String> setPermissions, List<Permission> permissions) {
		for (Permission permission : permissions) {
			if (permission.getInt(Permission.AVAILABLE) == 1) {
				setPermissions.add(permission.getStr(Permission.CODE));
			}
		}
	}

	/**
	 * 更新用户授权信息缓存.
	 */
	public void clearCachedAuthorizationInfo(Object principal) {
		SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName());
		clearCachedAuthorizationInfo(principals);
	}

	/**
	 * 清除所有用户授权信息缓存.
	 */
	public void clearAllCachedAuthorizationInfo() {
		Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
		if (cache != null) {
			for (Object key : cache.keys()) {
				cache.remove(key);
			}
		}
	}

}
